#include "OmPrerequisite.h"
#include "OmPublic.h"
#include "OmString.h"
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>

namespace OmPublic
{
	template <>
	OmExport void StringT<char, std::string>::format(const char * formatStr, ...)
	{		
		va_list vaList = 0;
		va_start(vaList, formatStr);
		size_t len = _vscprintf(formatStr, vaList) + 1;
		std::vector<char> buf(len, 0);
		int written=_vsnprintf(&buf[0], len, formatStr, vaList);
		if (written > 0)
		{
			mStr =&buf[0];
		}
		va_end(vaList);
	}

	template<>
	OmExport void StringT<wchar_t, std::wstring>::format(const wchar_t * formatStr, ...)
	{
		va_list vaList = 0;		
		va_start(vaList, formatStr);
		size_t len = _vscwprintf(formatStr, vaList) + 1;
		std::vector<wchar_t> buf(len, 0);
		int written=_vsnwprintf(&buf[0], len, formatStr, vaList);

		if (written > 0)
		{
			mStr =&buf[0];
		}
		va_end(vaList);
	}

	template<>
	OmExport StringT<char, std::string>::StringT(const char* str)
	{
		operator = (str);
	}

	template<>
	OmExport StringT<char, std::string>::StringT(const wchar_t * str)
	{
		if (!str)
			return ;
		size_t len = wcslen(str);
		char * tmp = new char[len * 2 + 1];
		memset(&tmp[len], 0, len+1);
		WideCharToMultiByte(CP_ACP, 0, str, len, tmp, len * 2, 0, 0);
		mStr = tmp;
		delete[] tmp;
	}

	template<>
	OmExport StringT<wchar_t ,std::wstring>::StringT(const char* str)
	{
		operator = (str);
	}

	template<>
	OmExport StringT<wchar_t, std::wstring>::StringT(const wchar_t* str)
	{
		if (!str)
			return;
		mStr = str;
	}
	
	template<>
	OmExport void StringT<char, std::string>::splitFileName(StringT & file, StringT & path, bool endWithSlash /* = false */) const
	{
		std::string::size_type pos = mStr.rfind("\\");
		if (pos == std::string::npos)
		{
			path.clear();
			file = mStr;
		}
		else
		{
			path = mStr.substr(0, endWithSlash ? pos + 1 : pos);
			file = mStr.substr(pos+1, mStr.length()-1 -pos );
		}
	}

	template<>
	OmExport void StringT<wchar_t, std::wstring>::splitFileName(StringT & file, StringT & path, bool endWithSlash /* = false */) const
	{
		std::wstring::size_type pos = mStr.rfind(L"\\");
		if (pos == std::wstring::npos)
		{
			path.clear();
			file = mStr;
		}
		else
		{
			path = mStr.substr(0, endWithSlash ? pos + 1 : pos);
			file = mStr.substr(pos+1, mStr.length()-1 -pos );
		}
	}

	template<>
	OmExport const StringT<wchar_t, std::wstring>& StringT<wchar_t, std::wstring>::operator = (const char * str)
	{
		if (!str)
			return (*this);
		size_t len = strlen(str);
		wchar_t * tmp = new wchar_t[len + 1];
		memset(&tmp[len/2], 0, (len - len /2 + 1)* sizeof(wchar_t));
		MultiByteToWideChar(CP_ACP, 0, str, len, tmp, len);
		mStr = tmp;
		delete[] tmp;
		return (*this);
	}

	template<>
	OmExport const StringT<char, std::string>& StringT<char, std::string>::operator = (const char * str)
	{
		if (!str)
			return (*this);
		mStr = str;
		return (*this);
	}

	template<>
	OmExport void StringT<char, std::string>::trimLeft()
	{
		const std::string s = " ";
		mStr.erase(mStr.find_last_not_of(s) + 1);
	}

	template<>
	OmExport void StringT<char, std::string>::trimRight()
	{		
		const std::string s = " ";
		mStr.erase(0, mStr.find_first_not_of(s));		
	}

	template<>
	OmExport void StringT<wchar_t, std::wstring>::trimLeft()
	{
		const std::wstring s = L" ";
		mStr.erase(mStr.find_last_not_of(s) + 1);
	}

	template<>
	OmExport void StringT<wchar_t, std::wstring>::trimRight()
	{
		const std::wstring s = L" ";
		mStr.erase(0, mStr.find_first_not_of(s));		
	}

/*
	//-----------------------------------------------------------------------
	const String StringUtil::BLANK;
	//-----------------------------------------------------------------------
	void StringUtil::trim(String& str, bool left, bool right)
	{
		/*
		size_t lspaces, rspaces, len = length(), i;

		lspaces = rspaces = 0;

		if( left )
		{
		// Find spaces / tabs on the left
		for( i = 0;
		i < len && ( at(i) == ' ' || at(i) == '\t' || at(i) == '\r');
		++lspaces, ++i );
		}

		if( right && lspaces < len )
		{
		// Find spaces / tabs on the right
		for( i = len - 1;
		i >= 0 && ( at(i) == ' ' || at(i) == '\t' || at(i) == '\r');
		rspaces++, i-- );
		}

		*this = substr(lspaces, len-lspaces-rspaces);
		* /
		static const String delims = " \t\r";
		if(right)
			str.erase(str.find_last_not_of(delims)+1); // trim right
		if(left)
			str.erase(0, str.find_first_not_of(delims)); // trim left
	}

	//-----------------------------------------------------------------------
	std::vector<String> StringUtil::split( const String& str, const String& delims, unsigned int maxSplits)
	{
		std::vector<String> ret;
		// Pre-allocate some space for performance
		ret.reserve(maxSplits ? maxSplits+1 : 10);    // 10 is guessed capacity for most case

		unsigned int numSplits = 0;

		// Use STL methods 
		size_t start, pos;
		start = 0;
		do 
		{
			pos = str.find_first_of(delims, start);
			if (pos == start)
			{
				// Do nothing
				start = pos + 1;
			}
			else if (pos == String::npos || (maxSplits && numSplits == maxSplits))
			{
				// Copy the rest of the string
				ret.push_back( str.substr(start) );
				break;
			}
			else
			{
				// Copy up to delimiter
				ret.push_back( str.substr(start, pos - start) );
				start = pos + 1;
			}
			// parse up to next real data
			start = str.find_first_not_of(delims, start);
			++numSplits;

		} while (pos != String::npos);



		return ret;
	}


	//-----------------------------------------------------------------------
	bool StringUtil::startsWith(const String& str, const String& pattern, bool lowerCase)
	{
		size_t thisLen = str.length();
		size_t patternLen = pattern.length();
		if (thisLen < patternLen || patternLen == 0)
			return false;

		String startOfThis = str.substr(0, patternLen);
		if (lowerCase)
			StringUtil::toLowerCase(startOfThis);

		return (startOfThis == pattern);
	}
	//-----------------------------------------------------------------------
	bool StringUtil::endsWith(const String& str, const String& pattern, bool lowerCase)
	{
		size_t thisLen = str.length();
		size_t patternLen = pattern.length();
		if (thisLen < patternLen || patternLen == 0)
			return false;

		String endOfThis = str.substr(thisLen - patternLen, patternLen);
		if (lowerCase)
			StringUtil::toLowerCase(endOfThis);

		return (endOfThis == pattern);
	}
	//-----------------------------------------------------------------------
	String StringUtil::standardisePath(const String& init)
	{
		String path = init;

		std::replace( path.begin(), path.end(), '\\', '/' );
		if( path[path.length() - 1] != '/' )
			path += '/';

		return path;
	}
	//-----------------------------------------------------------------------
	void StringUtil::splitFilename(const String& qualifiedName, 
		String& outBasename, String& outPath)
	{
		String path = qualifiedName;
		// Replace \ with / first
		std::replace( path.begin(), path.end(), '\\', '/' );
		// split based on final /
		size_t i = path.find_last_of('/');

		if (i == String::npos)
		{
			outPath.clear();
			outBasename = qualifiedName;
		}
		else
		{
			outBasename = path.substr(i+1, path.size() - i - 1);
			outPath = path.substr(0, i+1);
		}

	}
	//-----------------------------------------------------------------------
	void StringUtil::splitBaseFilename(const String& fullName, 
		String& outBasename, String& outExtention)
	{
		size_t i = fullName.find_last_of(".");
		if (i == String::npos)
		{
			outExtention.clear();
			outBasename = fullName;
		}
		else
		{
			outExtention = fullName.substr(i+1);
			outBasename = fullName.substr(0, i);
		}
	}
	// ----------------------------------------------------------------------------------------------------------------------------------------------
	void StringUtil::splitFullFilename(	const String& qualifiedName, 
		String& outBasename, String& outExtention, String& outPath )
	{
		String fullName;
		splitFilename( qualifiedName, fullName, outPath );
		splitBaseFilename( fullName, outBasename, outExtention );
	}
	//-----------------------------------------------------------------------


	*/

}